package com.qs.javame.thread1028.future;

/**
 * 手写Future模式
 */
public class TestFuture2 {

    public static void main(String[] args) {
        TestFuture2 client = new TestFuture2();
        Data futureData = client.request("张三");
        System.out.println(futureData.getResult());
    }


    public Data request(String data) {
        FutureData futureData = new FutureData();
        //启动一个线程，获取真实数据
        new Thread(() -> {
            RealData realData = new RealData(data);
            futureData.setRealData(realData);
        }).start();

        //无论是否将真实数据存储到futureData中，直接返回结果
        return futureData;
    }

}

//定义公共数据接口
interface Data {
    String getResult();
}


class FutureData implements Data {

    //标记真实数据是否准备好，准备好为true，没有准备好为false（这里的volatile加不加都可以，同步方法中，不存在线程安全问题）
    private volatile static boolean flag = false;

    private RealData realData;

    public synchronized void setRealData(RealData realData) {
        //数据准备好了，则直接返回
        if (flag) {
            return;
        }

        //数据没有准备好，则准备数据
        this.realData = realData;

        //数据准备好，则将标志位置为true，唤醒等待线程，表示可以获取到真实数据了
        flag = true;
        this.notify();
    }


    /**
     * 这里使用同步方法，锁对象为this
     */
    @Override
    public synchronized String getResult() {
        //真实数据没有准备好时，一直等待（注意锁对象为this，何时唤醒？）
        while (!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //真实数据准备好了，则直接返回正式数据
        return realData.getResult();
    }
}

/**
 * 真实结果类，通过RealData对象的getResult()方法可以获取真实的数据
 */
class RealData implements Data {

    private String result;

    public RealData(String data) {
        System.out.println("这是一个耗时的操作，正在构建data。。");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("操作完毕，获取结果。");
        result = "这个是结果。。";
    }


    @Override
    public String getResult() {
        return result;
    }
}